#include "glutproject.h"
#include "extension/colors.h"
#include "point.h"
#include "bmath.h"

#include <GL/gl.h>
#include <vector>
#include <map>
#include <iostream>
#include <string>
#include <fstream>
#include <cassert>

using namespace bend2d;
using namespace std;

class Plot : public GlutProject
{
    public:
        void SetColor(const Color& color)
        {
            float r,g,b,a;
            color.ToGLFloat(r,g,b,a);
            glColor4f(r,g,b,a);
        }

        void AddPoint(const string& serie, double x, double y)
        {
            m_Series[serie][x] = y;
            if(Math::Abs(x) > m_MaxValueX) m_MaxValueX = x;
            if(Math::Abs(y) > m_MaxValueY) m_MaxValueY = y;
        }

        void DoThePlot()
        {
            gluOrtho2D(-m_MaxValueX - m_MaxValueX / 10, m_MaxValueX + m_MaxValueX / 10, -m_MaxValueY - m_MaxValueY / 10, m_MaxValueY + m_MaxValueY / 10);
            
            glBegin(GL_LINES);
            SetColor(m_LineColor);
            glVertex2f(-m_MaxValueX, 0);
            glVertex2f(+m_MaxValueX, 0);
            glVertex2f(0, -m_MaxValueY);
            glVertex2f(0, +m_MaxValueY);
            glEnd();


            glLineWidth(2);
            glBegin(GL_LINES);
            SetColor(m_PlotColor);
            
            
            
            for(map<double, double>::iterator it = m_Points.begin(); it != m_Points.end();)
            {
                map<double, double>::iterator lit = it++;
                if(it == m_Points.end())
                    continue;
                glVertex2f(lit->first, lit->second);
                glVertex2f(it->first, it->second);
            }
            glEnd();
        }

        Plot() :
            m_LineColor(0x000000FF),
            m_PlotColor(0xFF0000FF),
            m_ResolutionX(10),
            m_ResolutionY(10),
            m_MaxValueX(0),
            m_MaxValueY(0)
        {
        }

        void ClearFunction()
        {
            glClearColor(1, 1, 1, 1);
            glClear(GL_COLOR_BUFFER_BIT);
        }

        void CustomRenderFunction()
        {
            glPushMatrix();
            DoThePlot();
            glPopMatrix();
        }

        void CustomIdleFunction()
        {
        }

        void SetOrtho()
        {
        }

    private:
        map<string, map<double, double> > m_Series;
        pair<double, double> m_ShowRangeX;
        pair<double, double> m_ShowRangeY;
        
        Color m_LineColor;
        Color m_PlotColor;
        double m_ResolutionX;
        double m_ResolutionY;
        double m_MaxValueX;
        double m_MaxValueY;
};


void loadFromFile(const string& filename, Plot& plot, const vector<string>& xcolumns, const vector<string>& ycolumns)
{
    ifstream infile(filename.c_str());

    if(infile.good())
    {
        vector<string> header;
        vector<vector<string> > data;
        string line;

        while(!infile.eof())
        {
            getline(infile, line);
            if(line.size())
            {
                vector<string> params;
                size_t pos = line.find(";");
                while(pos != string::npos)
                {
                    params.push_back(line.substr(0, pos));
                    line = line.substr(pos+1);
                    pos = line.find(";");
                }
    
                if(line.size())
                    params.push_back(line);

                if(header.size() == 0) 
                    header = params;
                else 
                    data.push_back(params);

                assert(header.size() == params.size());
            }
        }
    }
    else
    {
        cerr << "Bad filename\n";
        exit(-1);
    }
}

int main(int argc, char* argv[])
{
    Plot myPlot;
    loadFromFile(argv[1], myPlot, argv[2], argv[3]);

    myPlot.Init(argc, argv);
    myPlot.MainLoop();
    return 0;
}
